using System;
using System.Collections;
using System.Collections.Generic;

//
// * Copyright (c) 2002-2009 "Neo Technology,"
// *     Network Engine for Objects in Lund AB [http://neotechnology.com]
// *
// * This file is part of Neo4j.
// * 
// * Neo4j is free software: you can redistribute it and/or modify
// * it under the terms of the GNU Affero General Public License as
// * published by the Free Software Foundation, either version 3 of the
// * License, or (at your option) any later version.
// * 
// * This program is distributed in the hope that it will be useful,
// * but WITHOUT ANY WARRANTY; without even the implied warranty of
// * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// * GNU Affero General Public License for more details.
// * 
// * You should have received a copy of the GNU Affero General Public License
// * along with this program. If not, see <http://www.gnu.org/licenses/>.
// 
namespace org.neo4j.kernel.impl.util
{


// use array for first few properties to decrease memory footprint (and
// to some extent boost performance) for nodes/rels with few properties
	public class ArrayIntSet
	{
		private int maxRelSize = 256;
		private int[] rels = new int[2];

	// TODO: figure out if we need volatile here?
		private int arrayCount = 0;

		private HashSet<int> relationshipSet = null;

		public virtual bool add(int id)
		{
			for (int i = 0; i < arrayCount; i++)
			{
				if (rels[i] == id)
				{
					return false;
				}
			}
			if (arrayCount == rels.Length && rels.Length * 2 <= maxRelSize)
			{
				int[] newRels = new int[rels.Length * 2];
				System.Array.Copy(rels, 0, newRels, 0, rels.Length);
				rels = newRels;
			}
			if (arrayCount != -1)
			{
				if (arrayCount < rels.Length)
				{
					rels[arrayCount++] = id;
					return true;
				}
				relationshipSet = new HashSet<int>();
				for (int i = 0; i < arrayCount; i++)
				{
					relationshipSet.Add(rels[i]);
				}
				arrayCount = -1;
			}
			return relationshipSet.Add(id);
		}

        public virtual IEnumerator<int> iterator()
		{
			if (arrayCount == -1)
			{
				return relationshipSet.GetEnumerator();
			}
			return new ArrayIntIterator(rels, arrayCount);
		}

		public virtual bool remove(int id)
		{
			for (int i = 0; i < arrayCount; i++)
			{
				if (rels[i] == id)
				{
					int[] dest = rels;
					if (arrayCount - 1 < rels.Length / 3)
					{
						dest = new int[rels.Length / 2];
						System.Array.Copy(rels, 0, dest, 0, arrayCount);
					}
					if (i + 1 < dest.Length && (arrayCount - i - 1) > 0)
					{
						System.Array.Copy(rels, i + 1, dest, i, arrayCount - i - 1);
						rels = dest;
					}
					arrayCount--;
					return true;
				}
			}
			if (arrayCount == -1)
			{
				return relationshipSet.Remove(id);
			}
			return false;
		}

		public virtual IEnumerable<int> values()
		{
			if (arrayCount == -1)
			{
				return relationshipSet;
			}
			return new ArrayIntIterator(rels, arrayCount);
		}

        private class ArrayIntIterator : IEnumerator<int>, IEnumerable<int>
		{
			private int[] intArray;
			private int pos = -1;
			private int arrayCount;

			internal ArrayIntIterator(int[] array, int count)
			{
				this.intArray = array;
				this.arrayCount = count;
			}

			public virtual bool hasNext()
			{
				return pos + 1 < arrayCount;
			}

			public virtual int next()
			{
				return intArray[++pos];
			}

			public virtual void remove()
			{
				throw new UnsupportedOperationException();
			}

            public virtual IEnumerator<int> iterator()
			{
				return this;
			}

            #region Implementation of IDisposable

            /// <summary>
            /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
            /// </summary>
            /// <filterpriority>2</filterpriority>
            public void Dispose()
            {
                throw new NotImplementedException();
            }

            #endregion

            #region Implementation of IEnumerator

            /// <summary>
            /// Advances the enumerator to the next element of the collection.
            /// </summary>
            /// <returns>
            /// true if the enumerator was successfully advanced to the next element; false if the enumerator has passed the end of the collection.
            /// </returns>
            /// <exception cref="T:System.InvalidOperationException">The collection was modified after the enumerator was created. 
            ///                 </exception><filterpriority>2</filterpriority>
            public bool MoveNext()
            {
                throw new NotImplementedException();
            }

            /// <summary>
            /// Sets the enumerator to its initial position, which is before the first element in the collection.
            /// </summary>
            /// <exception cref="T:System.InvalidOperationException">The collection was modified after the enumerator was created. 
            ///                 </exception><filterpriority>2</filterpriority>
            public void Reset()
            {
                throw new NotImplementedException();
            }

            /// <summary>
            /// Gets the element in the collection at the current position of the enumerator.
            /// </summary>
            /// <returns>
            /// The element in the collection at the current position of the enumerator.
            /// </returns>
            public int Current
            {
                get { throw new NotImplementedException(); }
            }

            /// <summary>
            /// Gets the current element in the collection.
            /// </summary>
            /// <returns>
            /// The current element in the collection.
            /// </returns>
            /// <exception cref="T:System.InvalidOperationException">The enumerator is positioned before the first element of the collection or after the last element.
            ///                 </exception><filterpriority>2</filterpriority>
            object IEnumerator.Current
            {
                get { return Current; }
            }

            #endregion

            #region Implementation of IEnumerable

            /// <summary>
            /// Returns an enumerator that iterates through the collection.
            /// </summary>
            /// <returns>
            /// A <see cref="T:System.Collections.Generic.IEnumerator`1"/> that can be used to iterate through the collection.
            /// </returns>
            /// <filterpriority>1</filterpriority>
            public IEnumerator<int> GetEnumerator()
            {
                throw new NotImplementedException();
            }

            /// <summary>
            /// Returns an enumerator that iterates through a collection.
            /// </summary>
            /// <returns>
            /// An <see cref="T:System.Collections.IEnumerator"/> object that can be used to iterate through the collection.
            /// </returns>
            /// <filterpriority>2</filterpriority>
            IEnumerator IEnumerable.GetEnumerator()
            {
                return GetEnumerator();
            }

            #endregion
		}

		public virtual bool contains(int id)
		{
			for (int i = 0; i < arrayCount; i++)
			{
				if (rels[i] == id)
				{
					return true;
				}
			}
			if (arrayCount == -1)
			{
				return relationshipSet.Contains(id);
			}
			return false;
		}

		public virtual int size()
		{
			if (arrayCount != -1)
			{
				return arrayCount;
			}
			return relationshipSet.Count;
		}
	}

    internal class UnsupportedOperationException : Exception
    {
    }
}